/**
 * @file select
 * @author liaoxuezhi@baidu.com
 *
 * https://github.com/JedWatson/react-select
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  PureComponent,
  PropTypes
} from 'react';
import {fetch} from '../../renderer';
import ReactSelect from 'react-select';
import * as assign from 'object-assign';
import * as cx from 'classnames';
import {findByAttrValue, findIndexByAttrValue} from '../../../util/helper';
import {filterOptions} from '../util';
import {Enhance as FormItem} from '../form-item';
import {findDOMNode} from 'react-dom';
import {evalReturnExpression} from '../../util';

@FormItem({
  type: 'list',
  validateSchema: 'http://amis.baidu.com/schemas/form.json#/definitions/formItem'
})
export default class List extends PureComponent {
  static propTypes = {
    className: PropTypes.string,
    formMode: PropTypes.string,
    formHorizontal: PropTypes.object,
    joinValues: PropTypes.bool.isRequired,
    delimiter: PropTypes.string.isRequired
  };

  static defaultProps = {
    value: '',
    placeholder: '请选择',
    joinValues: true,
    delimiter: ',',
    imageClassName: 'thumb-md',
    clearable: true
  };

  static contextTypes = {
    combo: PropTypes.object
  };

  constructor(props) {
    super(props);

    this.state = {
      options:  props.sourceLocalData ? filterOptions(props.sourceLocalData, props.data) : (filterOptions(props.options, props.data) || [])
    };

    this.changeValue = this.changeValue.bind(this);
    this.loadRemote = this.loadRemote.bind(this);
  }

  componentWillMount() {
    const {
      unique,
      name
    } = this.props;
    const combo = this.context.combo;

    if (unique && combo) {
      combo.registerUnique(name, this);
      this.setState({
        options: combo.getRestOptions(name, this)
      });
    }
  }

  componentWillReceiveProps(nextProps) {
    const props = this.props;
    const combo = this.context.combo;

    if (props.sourceFetching && !nextProps.sourceFetching && nextProps.sourceData) {
      const sourceData = nextProps.sourceData;
      let options = filterOptions(sourceData && sourceData.hasOwnProperty('options') ? sourceData.options : sourceData);

      if (nextProps.unique && combo) {
        combo.registerUnique(nextProps.name, this, options);
        options = combo.getRestOptions(nextProps.name, this);
      }

      this.setState({
        rawOptions: sourceData && sourceData.hasOwnProperty('options') ? sourceData.options : sourceData,
        options
      }, () => sourceData.hasOwnProperty('value') && this.props.setValue(sourceData.value));
    }

    if (props.options !== nextProps.options || props.sourceLocalData !== nextProps.sourceLocalData) {
      let options = filterOptions(nextProps.sourceLocalData || nextProps.options, nextProps.data) || [];

      if (nextProps.unique && combo) {
        combo.registerUnique(nextProps.name, this, options);
        options = combo.getRestOptions(nextProps.name, this);
      }

      this.setState({
        options
      });
    } else if (props.data !== nextProps.data) {
      let options = filterOptions(this.state.rawOptions || nextProps.sourceLocalData || nextProps.options, nextProps.data);

      if (nextProps.unique && combo) {
        combo.registerUnique(nextProps.name, this, options);
        options = combo.getRestOptions(nextProps.name, this);
      }

      this.setState({
        options
      });
    }
  }

  componentWillUnmount() {
    const {
      unique,
      name
    } = this.props;
    const combo = this.context.combo;

    if (unique && combo) {
      combo.unRegisterUnique(name, this);
    }
  }

  changeValue(newValue) {
    let {
      joinValues,
      delimiter,
      multiple,
      value,
      clearable
    } = this.props;
    const options = this.state.options;
    const multi = multiple || this.props.multi;

    if (multi) {
      if (joinValues && value && typeof value === 'string') {
        value = value.split(delimiter).map(item => findByAttrValue(options, 'value', item));
      }

      const originValue = value && Array.isArray(value) && value.concat() || [];
      const idx = findIndexByAttrValue(originValue, 'value', newValue.value);

      if (~idx) {
        originValue.splice(idx, 1);
      } else {
        originValue.push(newValue);
      }

      newValue = joinValues ? originValue.map(item => item.value).join(delimiter) : originValue;
    } else {
      newValue = joinValues ? newValue.value : newValue;
      newValue = newValue === value && clearable ? '' : newValue;
    }

    this.props.setValue(newValue);
  }

  loadRemote(input) {
    const {
      autoComplete
    } = this.props;

    return fetch(autoComplete, {term: input})
      .then(ret => ({
        options: ret.data
      }))
  }

  renderInput(props) {
    const {
      options,
      placeholder,
      disabled,
      value,
      imageClassName,
      multiple,
      joinValues,
      delimiter,
      className
    } = props;

    if (!options || !options.length) {
      return (
        <p className="placeholder">{placeholder}</p>
      );
    }

    const selected = value ?

      (
        typeof value === 'string' && joinValues

          ? value.split(delimiter)

          : (
            multiple ? (
                Array.isArray(value) && !joinValues ? value.map(item => item.value) : []
              ) : (
                joinValues ? [value] : [value.value || value]
              )
          )
      )

      : [];

    return (
      <div className={cx('input-list clearfix', className, disabled ? 'disabled' : '')}>
        {options.map((item, key) => (
          <div
            key={key}
            className={cx('input-list-item pull-left', {
              active: !!~selected.indexOf(item.value),
              disabled
            })}
            onClick={() => item.disabled || disabled || this.changeValue(item)}
          >
            {item.image ? (<div className={imageClassName}><img src={item.image} className="w-full img-rounded" alt={item.label} /></div>) : null}
            {item.label ? (<div>{item.label}</div>) : null}
          </div>
        ))}
      </div>
    );
  }

  render() {
    const {
      name,
      placeholder,
      disabled,
      inline,
      multiple,
      multi,
      joinValues,
      delimiter,
      inputClassName,
      imageClassName
    } = this.props;

    const options = this.state.options;
    let value = this.props.getValue();
    value = typeof value === 'number' ? String(value) : value;

    const inputProps = {
      name, placeholder,
      options: options || [],
      value: value,
      onChange: this.changeValue,
      disabled,
      className: inputClassName || inline && 'w-auto inline',
      imageClassName,
      joinValues,
      delimiter,
      multiple: multiple || multi
    };

    return this.renderInput(inputProps);
  }
}
